package edu.office.applicationRepository;

import edu.office.entities.*;
import edu.office.tools.EOMessage;
import edu.office.tools.EOMessage1;
import edu.office.tools.StaticFields;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import org.jgrapht.Graph;
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
import org.jgrapht.graph.DefaultEdge;

import java.time.Duration;
import java.time.LocalDate;
import java.util.*;

@Named("testpaperRepositoryA")
@ApplicationScoped
public class TestpaperRepository extends ApplicationCommonRepository<Testpaper>{
    @Inject
    StudenttestpaperRepository studenttestpaperRepository;
    @Inject
    SubjectRepository subjectRepository;
    @Inject
    KnowledgeRepository knowledgeRepository;
    @Inject
    QuestionRepository questionRepository;
    @Inject
    StudentRepository studentRepository;
    @Inject
    LeadpointRepository leadpointRepository;
    @Inject
    WrongquestionCollectionRepository wrongquestionCollectionRepository;
    final int shortPath = 2;

    public TestpaperRepository() {
    }

    public List<Testpaper> getTestpaper4SchoolSubject(Integer schoolId, Integer subjectId, boolean isTestpaper) {
        return find("select * from testpaper where schoolid=" + schoolId
                + " and istest=" + isTestpaper
                + " and (locate('" + subjectId+ ",',subjectids)>0 "
                + "or locate('," + subjectId+ "',subjectids)>0 "
                + "or ( locate('" + subjectId+ "',subjectids)>0 "
                + " and locate(',',subjectids)<=0) ) ").list();
    }

    public String createHandmakeTestpaper(
            Set<Student> selectedStudent, Testpaper testpaper,
            List<Question> selectedQuestions) {
        if (isPropertiesofTestpaperOk(testpaper)) {
            create(testpaper);
            selectedStudent.forEach((student) -> studenttestpaperRepository.generateTestpaper4Question(
                    selectedQuestions, student, testpaper));
            return EOMessage.getEOMessageENUM(EOMessage1.Finished);
        } else {
            return EOMessage.getEOMessageENUM(EOMessage1.Failed);
        }

    }

    private boolean isPropertiesofTestpaperOk(Testpaper testpaper) {
        //看时间设置是否合适
        Duration duration = Duration.between(testpaper.getENDTIME(), testpaper.getSTARTTIME());
        long minitueInterval = duration.toMinutes();
        if (minitueInterval <= testpaper.getSPECIFIED_INTERVAL()
                || Calendar.getInstance().after(testpaper.getSTARTTIME())
                || testpaper.getSTARTTIME().isAfter(testpaper.getENDTIME())
        ) {
            System.out.println("Time Error");
            return false;
        }
        return true;
    }

    public String creatTestpapers4TeachSchool(Testpaper testpaper) {//Finished the test paper
        //Create testpapers according to school
        //1. According to the logined teacher and school, get the subjects in this semester
        //2. According to the subjects, get the knowledges;
        Set<Knowledge> knowledgesList = new HashSet<>();
        subjectRepository.getSubjectList4Testpaper(testpaper).forEach((subject) -> knowledgesList.addAll(knowledgeRepository.getKnowledgeList4Subject(subject)));
        //remove those knowledge that named as "start" and "end" and those without questionSet
        List<Knowledge> toBeRemovedKnowledges = new LinkedList<>();
        for (Knowledge knowledge : knowledgesList) {
            if (questionRepository.find("KNOWLEDGE_ID", knowledge.getID()).list().isEmpty()) {
                toBeRemovedKnowledges.add(knowledge);
            }
        }
        for (Knowledge toBeRemovedKnowledge : toBeRemovedKnowledges) {
            knowledgesList.remove(toBeRemovedKnowledge);
        }
        //3. According to the knowledges, get the testpapers for every student
        create(testpaper);
        //如果知识点数目大于分数要求，则去除距离最近的知识点
        if (knowledgesList.size() > testpaper.getSCORE()) {
            List<Knowledge> knowledge2BeRemoved = dealWithDuplicateKnowledge(testpaper);
            for (Knowledge k : knowledge2BeRemoved) {
                knowledgesList.remove(k);
                if (knowledgesList.size() < testpaper.getSCORE() / 2) {
                    //知识点数目不能太少
                    break;
                }
            }
        }
        studentRepository.list("SCHOOL_ID",testpaper.getSCHOOLID()).forEach((student) -> studenttestpaperRepository.generateTestpaper4KnowledgeList(knowledgesList, student, testpaper));
        return EOMessage.getEOMessageENUM(EOMessage1.Finished);
    }

    private List<Knowledge> dealWithDuplicateKnowledge(Testpaper testpaper) {
        List<Knowledge> reultList = new LinkedList<>();
        HashMap<Knowledge, List<Knowledge>> knowledgLessThreshold ;//存储距离小于阈值的知识点
        Set<Subject> subjectSet = subjectRepository.getSubjectList4Testpaper(testpaper);
        for (Subject subject : subjectSet) {
            Graph<Knowledge, DefaultEdge> directedGraph = subjectRepository.getGraphofKnowledge(subject);
            knowledgLessThreshold = new HashMap<>();
            List<Knowledge> temKnowledges =knowledgeRepository.list("SUBJECT_ID",subject.getID());
            for (Knowledge k1 : temKnowledges) {
                for (Knowledge k2 : temKnowledges) {
                    if (!k1.equals(k2)) {
                        double path = new DijkstraShortestPath<>(directedGraph).getPath(k1, k2).getLength();
                        if (path < shortPath) {//两个知识点间的距离小于指定定距离
                            if (null != knowledgLessThreshold.get(k1)) {
                                System.out.println("g");
                            } else {
                                knowledgLessThreshold.put(k1, new LinkedList<>());
                                knowledgLessThreshold.get(k1).add(k2);
                            }
                        }
                    }
                }
            }
            //删除哪个的策略
            List<Knowledge> knowledgeList=knowledgeRepository.list("SUBJECT_ID",subject.getID());
            for (Knowledge k1 : knowledgeList) {
                if (knowledgLessThreshold.get(k1) == null || knowledgLessThreshold.get(k1).isEmpty()) {
                    continue;
                }
                for (Knowledge k2 : knowledgLessThreshold.get(k1)) {
                    if (null == knowledgLessThreshold.get(k2) || knowledgLessThreshold.get(k2).isEmpty()) {
                        reultList.add(k1);
                        continue;
                    }
                    int size1 = knowledgLessThreshold.get(k1).size();
                    int size2 = knowledgLessThreshold.get(k2).size();
                    if (size1 > size2) {
                        reultList.add(k1);
                    } else {
                        reultList.add(k2);
                    }
                }
            }
        }
        return reultList;
    }

    public Testpaper creatTestpapersForStudent(boolean according2Leadpoint, Student student, Subject subject) {
        Testpaper result = new Testpaper();
        result.setCREATE_DATE(LocalDate.now());
        result.setSPECIFIED_INTERVAL(100);
        result.setISTEST(false);
        result.setSCHOOLID(student.getId());
        result.setSCORE(100);
        result.setSUBJECTIDS(String.valueOf(subject.getID()));
        result.setDEGREE(2);
        //2. According to the subjects, get the knowledges;
        Set<Knowledge> knowledgeCandiSet = new HashSet<>();
        if (according2Leadpoint) {//Knowledge list is from the leadpoint
            Leadpoint leadpoint = leadpointRepository.getLeadpointFront4Subject4Student(subject, student);
            knowledgeCandiSet.addAll(knowledgeRepository.getKnowledgesList4LeadingPoint(leadpoint));
        } else {
            //写入错题集里面的所有的知识点
            //错题-->知识点A且课程subject
            List<WrongquestionCollection> questionIds = wrongquestionCollectionRepository.list("select QUESTION_ID from WRONGQUESTION_COLLECTION where STUDENT_ID=?1", student.getId());
            StringBuilder ids = new StringBuilder();
            for (WrongquestionCollection wrq : questionIds) {
                ids.append(",").append(wrq.getQUESTION_ID());
            }
            if (ids.toString().contains(",")) {//有错题
                List<Question> questions = questionRepository.list("select * from QUESTION where id in (" + ids.substring(1) + ")");
                StringBuilder kIds = new StringBuilder();
                for (Question question : questions) {
                    kIds.append(",").append(question.getKNOWLEDGE_ID());
                }
                knowledgeCandiSet.addAll(knowledgeRepository.find("Select * from KNOWLEDGE where id in (" + kIds.substring(1) + ") and SUBJECT_ID=" + subject.getID()).list());
            } else {//没有错题
                knowledgeCandiSet.addAll(knowledgeRepository.listAll());
            }
            List<Knowledge> toBeRemovedKnowledges = new LinkedList<>();
            for (Knowledge knowledge : knowledgeCandiSet) {
                if (questionRepository.find("KNOWLEDGE_ID", knowledge.getID()).list().isEmpty()) {
                    toBeRemovedKnowledges.add(knowledge);
                }
            }
            toBeRemovedKnowledges.forEach(knowledgeCandiSet::remove);
            //3. According to the knowledges, get the testpapers for every student
            create(result);
            if (knowledgeCandiSet.isEmpty()) {//Generate knowledge list
                knowledgeCandiSet = new HashSet<>(knowledgeRepository.getKnowledgeList4Subject(subject));
                //Sample knowledges from list
                HashSet<Knowledge> knowledgeSet = new HashSet<>();
                Random random = new Random();
                for (Knowledge knowledge : knowledgeCandiSet) {//For every subject
                    if (random.nextFloat() > 0.5) knowledgeSet.add(knowledge);
                    if (knowledgeSet.size() > StaticFields.QuestionCount) break;
                }
                knowledgeCandiSet = knowledgeSet;
            }
            studenttestpaperRepository.generateTestpaper4KnowledgeList(knowledgeCandiSet, student, result);
            System.out.println("Finished");

        }
        return result;
    }

}
